package com.wsepr.flexreport.core
{
    import flash.utils.describeType;
    import flash.utils.getDefinitionByName;
    
    import mx.controls.CheckBox;
    import mx.controls.ComboBox;
    import mx.controls.DateChooser;
    import mx.controls.DateField;
    import mx.controls.LinkButton;
    import mx.controls.MenuBar;
    import mx.controls.PopUpButton;
    import mx.controls.RadioButton;
    import mx.controls.RichTextEditor;
    import mx.controls.Tree;
    import mx.core.Container;
    import mx.core.UIComponent;
    import mx.utils.StringUtil;
    
    import r1.deval.D;
    
    import spark.components.Group;
    import spark.components.SkinnableContainer;
    import spark.components.supportClasses.SkinnableTextBase;
    import spark.components.supportClasses.TextBase;

    public class MxmlParser
    {
        /*************用于加载类库 begin*************/
        
        private static const libMenuBar:MenuBar = new MenuBar;
        private static const libTree:Tree = new Tree;
        private static const libDateChooser:DateChooser = new DateChooser();
        private static const libDateField:DateField = new DateField();
        private static const libComboBox:ComboBox = new ComboBox();
        private static const libRadioButton:RadioButton = new RadioButton();
        private static const libCheckBox:CheckBox = new CheckBox;
        private static const libLinkButton:LinkButton = new LinkButton();
        private static const libPopUpButton:PopUpButton = new PopUpButton();
        private static const libRichTextEditor:RichTextEditor = new RichTextEditor();
        
        
        /*************用于加载类库 end*************/
        
        private const NAME_SPACE_MAPPING:Object={
            'library://ns.adobe.com/flex/mx':['mx.containers.','mx.controls.','mx.controls.dataGridClasses.'],
            'library://ns.adobe.com/flex/spark':['spark.components.']
        };
        
        private var _mxml:XML;
        
        public function MxmlParser(mxml:Object){
            if(mxml == null){
                return;
            }
            this.mxml = mxml;
        }
        
        /**
         * 解析mxml字符串，创建组件
         * */
        public function parseMXML():FlexPage{
            var page:FlexPage = new FlexPage();
            if(this._mxml == null){
                return page;
            }
            
            var component:Object = createControl(this._mxml);
            var root:Element = new Element();
            root.data = component;
            root.type = ElementType.CONTAINER;
            root.tagName = this._mxml.localName();
            //遍历所有节点，构建树形数据结构
            visitNode(this._mxml.children(), root);
            //遍历visitNode生成的数据结构，构建flex控件树
            buildControlTree(root, page);
            //设置根节点
            page.putComponentToContext(component);
            page.ui = component as UIComponent;
            return page;
        }
        
        /**
        * 构建flex控件树
        * */
        private function buildControlTree(parent:Element, page:FlexPage):void{
            for each(var e:Element in parent.children){
                if(parent.type == ElementType.CONTAINER && (e.type==ElementType.COMPONENT || e.type==ElementType.CONTAINER)){
                    addChild(e.toUIComponent(), parent.toUIComponent());
                }else if(parent.type == ElementType.COMPONENT || parent.type == ElementType.OBJECT){
                    if(e.type == ElementType.TEXT){
                        //先获取默认属性DefaultProperty 再赋值
                        if(parent.data is SkinnableTextBase || parent.data is TextBase){
                            parent.data['text'] = (e.data == null ? '' : e.data.toString()); 
                        }
                    }else if(e.type == ElementType.PROPERTY){//处理属性标签
                        var classInfo:XML = describeType(parent.data);
                        var propertyName:String = e.tagName;
                        var varType:String = classInfo.accessor.(@name==propertyName).@type;//属性类型
                        if(varType == 'Array'){
                            var val:Array = [];
                            for each(var child:Element in e.children){
                                val.push(child.data);
                            }
                            //设置属性值
                            parent.data[propertyName] = val;
                        }else if(varType == 'mx.core::IFactory'){//内嵌组件
                            trace('内嵌组件');
                            if(e.children.length > 0){
                                var componentTag:Element = e.children[0];
                                if(componentTag.tagName != 'Component' && componentTag.type != ElementType.FX_TAG){
                                    //报错，itemRenderer下必须有Component标签
                                    trace('itemRenderer下必须有Component标签');
                                }else{
                                    if(componentTag.children.length == 1){
                                        parent.data[propertyName] = new ComponentFactory(componentTag.data);
                                    }else{
                                        //报错，自定义标签Component下必须有且只有一个标签
                                        trace('自定义标签Component下必须有且只有一个标签');
                                    }
                                }
                            }
                        }
                    }
                }
                if(page != null){
                    page.putComponentToContext(e.data);
                }
                if(e.children.length > 0){
                    buildControlTree(e, page);
                }
            }
        }
        
        //遍历所有节点
        private function visitNode(children:XMLList, parent:Element):void{
            var nextParent:Object = null;
            var elem:Element;
            var component:Object;
            for each(var xml:XML in children){
                if(xml.nodeKind() == 'element'){
                    elem = new Element();
                    var result:Object = getElementType(xml, parent);
                    elem.type = result.type;
                    component = result.component;
                    if(elem.type == -1){
                        continue;
                    }
                    elem.data = component;
                    elem.parent = parent;
                    elem.tagName = xml.localName();
                    parent.addChild(elem);
                    
                    if(xml.children().length() > 0 && parent.type != ElementType.FX_TAG){
                        visitNode(xml.children(), elem);
                    }
                }else if(xml.nodeKind() == 'text'){
                    //文本节点
                    elem = new Element();
                    elem.type = ElementType.TEXT;
                    elem.data = xml.toString();
                    elem.parent = parent;
                    elem.tagName = xml.localName();
                    parent.addChild(elem);
                }
            }
        }
        
        //根据上下文判断节点的类型
        private function getElementType(xml:XML, parent:Element):Object{
            var result:Object = {component:null, type:-1};
            var component:Object = null;
            var type:int;
            trace('命名空间:'+xml.namespace());
            if(isFxNamespace(xml)){
                result.type = ElementType.FX_TAG;
                if(xml.localName() == 'Component'){
                    component = new MxmlParser(xml.children());
                }
                result.component = component;
                return result;
            }
            switch(parent.type){
                case ElementType.FX_TAG://fx标签
                case ElementType.CONTAINER://容器
                    component = createControl(xml);
                    if(component == null){
                        return -1;//在容器下面的必须是控件，否则忽略
                    }
                    type = isContainer(component) ? ElementType.CONTAINER : ElementType.COMPONENT;
                    break;
                case ElementType.COMPONENT://一般控件
                    type = ElementType.PROPERTY;
                    break;
                case ElementType.PROPERTY://属性标签
                    component = createControl(xml);
                    if(component != null && component is UIComponent){
                        if(isContainer(component)){
                            type = ElementType.CONTAINER;
                        }else{
                            type = ElementType.COMPONENT;
                        }
                    }else{
                        type = ElementType.OBJECT;
                    }
                    break;
                case ElementType.OBJECT:
                    type = ElementType.PROPERTY;
                    break;
                default:
                    type = ElementType.OBJECT;
            }
            result.type = type;
            result.component = component;
            return result;
        }
        
        //判断是否是容器
        private function isContainer(component:Object):Boolean{
            return component is SkinnableContainer || component is Group || component is Container;
        }
        
        //创建组件
        private function createControl(xml:XML):Object{
            var name:String = xml.localName();
            var namespace:String = xml.namespace();
            var packageList:Array = NAME_SPACE_MAPPING[namespace];
            var component:Object=null;
            if(packageList){
                var classReference:Class;
                for(var i:int=0;i<packageList.length;i++){
                    try{
                        classReference = Class(getDefinitionByName(packageList[i]+name));
                        component = new classReference();//大部分情况或返回UIComponent，但如果是属性标签时则可能是其他类型
                        setProperty(xml, component);
                        return component;
                    }catch(e1:ReferenceError){
                        continue;
                    }catch(e:Error){
                        trace(e.getStackTrace());
                        throw e;
                    }
                }
            }
            return component;
        }
        
        //设置组件属性
        private function setProperty(xml:XML, component:Object):void{
            var attrs:XMLList = xml.attributes();
            var propertyName:String;
            var propertyValue:String;
            for(var i:int=0;i<attrs.length();i++){
                trace('设置属性值:'+attrs[i].name()+" : "+ attrs[i]);
                propertyName = attrs[i].name();
                propertyValue = attrs[i];
                //先判断是否存在该属性
                if(!component.hasOwnProperty(propertyName)){
                    continue;
                }
                //长度或高度是百分比
                if((propertyName == 'width' || propertyName == 'height') && isPercent(propertyValue)){
                    propertyName = 'percent'+firstCharToUpper(propertyName);
                    propertyValue = propertyValue.replace('%','');
                }
                try{
                    component[propertyName] = propertyValue
                }catch(e:Error){
                    trace(e.getStackTrace());
                }
            }
        }
        
        //添加组件
        private function addChild(component:UIComponent, parent:UIComponent):void{
            if(parent is SkinnableContainer){
                //spark组件
                var container:SkinnableContainer = parent as SkinnableContainer;
                container.addElement(component);
            }else if(parent is Group){
                //halo组件
                var group:Group = parent as Group;
                group.addElement(component);
            }else if(parent is Container){
                //halo组件
                var haloContainer:Container = parent as Container;
                haloContainer.addChild(component);
            }
        }
        
        public function set mxml(mxml:*):void{
            if(mxml is String){
                this._mxml = new XML(mxml.toString());
            }else if(mxml is XMLList){
                this._mxml = (mxml as XMLList)[0];
            }else if(mxml is XML){
                this._mxml = mxml as XML;
            }
        }
        
        public function get mxml():XML{
            return this._mxml;
        }
        
        //判断是否百分比格式
        private function isPercent(val:String):Boolean{
            return val.indexOf('%') == val.length - 1;
        }
        
        //首字母大写
        private function firstCharToUpper(s:String):String{
            return s.replace(/(\w)/,function($0:String, $1:String, $2:String, $3:String):String{
                return $1.toUpperCase();
            });
        }
        
        //判断是否fx的命名控件
        private function isFxNamespace(xml:XML):Boolean{
            var flag:Boolean = xml.namespace().toString() == 'http://ns.adobe.com/mxml/2009';
            return flag;
        }
    }
}